package com.seguriapp.entitieslist.gwt.client;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.google.gwt.core.client.Callback;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.geolocation.client.Geolocation;
import com.google.gwt.geolocation.client.Position;
import com.google.gwt.geolocation.client.PositionError;
import com.google.gwt.maps.client.InfoWindow;
import com.google.gwt.maps.client.InfoWindowContent;
import com.google.gwt.maps.client.MapOptions;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.control.SmallMapControl;
import com.google.gwt.maps.client.event.MarkerClickHandler;
import com.google.gwt.maps.client.geom.LatLng;
import com.google.gwt.maps.client.geom.Size;
import com.google.gwt.maps.client.overlay.Marker;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.ColumnSortEvent.AsyncHandler;
import com.google.gwt.user.cellview.client.ColumnSortList;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.AsyncDataProvider;
import com.google.gwt.view.client.HasData;
import com.seguriapp.common.gwt.client.celltable.SeguriAppCellTable;
import com.seguriapp.common.gwt.client.pagination.SearchPagination;
import com.seguriapp.entities.District;
import com.seguriapp.entities.SeguriAppEntity;
import com.seguriapp.entities.SeguriAppEntityType;
import com.seguriapp.entitieslist.gwt.client.activity.EntitiesListActivity;
import com.seguriapp.entitieslist.gwt.client.activity.EntitiesListActivity.Display;

public class EntitiesListPage extends Composite implements Display {

  private static final Logger LOG = Logger.getLogger(EntitiesListPage.class.getName());
  private static final String SELECTED_MENU_STYLE = "selectedMenu";

  private static EntitiesListPageUiBinder uiBinder = GWT.create(EntitiesListPageUiBinder.class);

  interface EntitiesListPageUiBinder extends UiBinder<Widget, EntitiesListPage> {
  }

  @UiField
  protected HTMLPanel listViewPanel;
  @UiField
  protected HTMLPanel mapViewPanel;
  @UiField
  protected HTMLPanel mapPanel;
  @UiField
  protected HTMLPanel entitiesGridPanel;
  @UiField
  protected HTMLPanel selectedDistrictsPanel;
  @UiField
  protected InlineLabel noDataLabel;
  @UiField
  protected SearchPagination pagination;
  @UiField
  protected ListBox entityTypeLB;
  @UiField
  protected Anchor listViewLink;
  @UiField
  protected Anchor mapViewLink;

  private CellTable<SeguriAppEntity> entitiesGrid;
  private TextColumn<SeguriAppEntity> namesColumn;
  private TextColumn<SeguriAppEntity> phoneColumn;
  private TextColumn<SeguriAppEntity> addressColumn;
  private TextColumn<SeguriAppEntity> districtColumn;
  private MapWidget map;
  private HTMLPanel districtListOption = new HTMLPanel("");

  private EntitiesListActivity presenter;

  public EntitiesListPage() {
    initWidget(uiBinder.createAndBindUi(this));
    initializeColumns();
    initializeGridData();
    inicializeHandlers();
  }

  private void initializeColumns() {
    namesColumn = new TextColumn<SeguriAppEntity>() {

      @Override
      public String getValue(final SeguriAppEntity alert) {
        return alert.getTitle();
      }
    };

    phoneColumn = new TextColumn<SeguriAppEntity>() {

      @Override
      public String getValue(final SeguriAppEntity alert) {
        return alert.getPhone();
      }
    };

    addressColumn = new TextColumn<SeguriAppEntity>() {

      @Override
      public String getValue(final SeguriAppEntity alert) {
        return alert.getAddress();
      }
    };

    districtColumn = new TextColumn<SeguriAppEntity>() {

      @Override
      public String getValue(final SeguriAppEntity alert) {
        return alert.getDistrict().getName();
      }
    };

    namesColumn.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
    phoneColumn.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
    addressColumn.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
    districtColumn.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);

    namesColumn.setSortable(true);
    phoneColumn.setSortable(true);
    addressColumn.setSortable(true);
    districtColumn.setSortable(true);

  }

  private void initializeGridData() {
    generateTable();
    entitiesGridPanel.clear();
    entitiesGridPanel.add(entitiesGrid);
  }

  private void generateTable() {
    entitiesGrid = new SeguriAppCellTable<SeguriAppEntity>();
    entitiesGrid.addColumn(namesColumn, "Entidad");
    entitiesGrid.addColumn(phoneColumn, SafeHtmlUtils.fromTrustedString("Tel&eacute;fono"));
    entitiesGrid.addColumn(addressColumn, SafeHtmlUtils.fromTrustedString("Direcci&oacute;n"));
    entitiesGrid.addColumn(districtColumn, "Distrito");
    entitiesGrid.setColumnWidth(namesColumn, "30%");
    entitiesGrid.setColumnWidth(phoneColumn, "15%");
    entitiesGrid.setColumnWidth(addressColumn, "40%");
    entitiesGrid.setColumnWidth(districtColumn, "15%");
  }

  private void updateListData() {
    final List<Long> idsList = getSelectedList();
    LOG.log(Level.INFO, "updateEntitiesData");
    presenter.updateEntitiesData(idsList, new Long(entityTypeLB.getValue(entityTypeLB.getSelectedIndex())));
  }

  private List<Long> getSelectedList() {
    final List<Long> idsList = new ArrayList<Long>();
    for (int i = 0; i < districtListOption.getWidgetCount(); i++) {
      final CheckBox checkbox = (CheckBox) districtListOption.getWidget(i);
      if (checkbox.getValue()) {
        idsList.add(new Long(checkbox.getFormValue()));
      }
    }
    return idsList;
  }

  private void inicializeHandlers() {
    final AsyncDataProvider<SeguriAppEntity> dataProvider = new AsyncDataProvider<SeguriAppEntity>() {

      @Override
      protected void onRangeChanged(HasData<SeguriAppEntity> display) {

        // Get the ColumnSortInfo from the table.
        final ColumnSortList sortList = entitiesGrid.getColumnSortList();
        if (sortList.size() > 0) {
          presenter.setAscending(sortList.get(0).isAscending());
          if (sortList.get(0).getColumn().equals(namesColumn)) {
            presenter.setColumnSort("title");
          } else if (sortList.get(0).getColumn().equals(phoneColumn)) {
            presenter.setColumnSort("phone");
          } else if (sortList.get(0).getColumn().equals(addressColumn)) {
            presenter.setColumnSort("address");
          } else if (sortList.get(0).getColumn().equals(districtColumn)) {
            presenter.setColumnSort("district");
          }
          updateListData();
        }
      }
    };

    dataProvider.addDataDisplay(entitiesGrid);

    // Add a ColumnSortEvent.AsyncHandler to connect sorting to the
    // AsyncDataPRrovider.
    final AsyncHandler columnSortHandler = new AsyncHandler(entitiesGrid);
    entitiesGrid.addColumnSortHandler(columnSortHandler);
  }

  public SearchPagination getPagination() {
    return pagination;
  }

  public void setPresenter(final EntitiesListActivity presenter) {
    this.presenter = presenter;
  }

  public void setEntityTypesFilter(final List<SeguriAppEntityType> entityTypesList) {
    entityTypeLB.clear();
    if (entityTypesList != null) {
      for (final SeguriAppEntityType type : entityTypesList) {
        entityTypeLB.addItem(type.getName(), type.getId().toString());
      }
    }
    entityTypeLB.addChangeHandler(new ChangeHandler() {
      public void onChange(final ChangeEvent event) {
        LOG.log(Level.INFO, "entityTypeLB onChange");
        updateListData();
      }
    });
  }

  public void setGridData(final List<SeguriAppEntity> entitiessList) {
    noDataLabel.setVisible(false);
    entitiesGridPanel.setVisible(true);
    entitiesGrid.setRowData(0, entitiessList);
    entitiesGrid.setRowCount(entitiessList.size(), true);
  }

  public void setMapData(final List<SeguriAppEntity> entitiessList, final double defaultLat, final double defaultLng, final int zoomValue, final boolean getUserLocation) {
    final MapOptions mapOptions = MapOptions.newInstance();
    mapOptions.setSize(Size.newInstance(500, 400));

    map = new MapWidget(LatLng.newInstance(defaultLat, defaultLng), zoomValue, mapOptions);
    map.setScrollWheelZoomEnabled(true);
    map.addControl(new SmallMapControl());
    if (getUserLocation) {
      getUserLocation();
    }
    mapPanel.clear();
    mapPanel.add(map);
    setListItem(entitiessList);
  }

  public void setPagination(final long currentPage, final long totalPages, final long maxPages) {
    pagination.setPagination(currentPage, totalPages, maxPages);
  }

  public void showNoDataMessage() {
    noDataLabel.setVisible(true);
    entitiesGridPanel.setVisible(false);
    if (map != null) {
      map.clearOverlays();
    }
  }

  public void setDistrictsListFilter(final List<District> districtsList) {
    districtListOption.clear();
    if (districtsList != null && !districtsList.isEmpty()) {
      for (final District district : districtsList) {
        final CheckBox checkBox = new CheckBox(district.getName());
        checkBox.setFormValue(district.getId().toString());
//        checkBox.addClickHandler(districtListOptionHandler);
        districtListOption.add(checkBox);
      }
    }
  }

  @UiHandler("listViewLink")
  protected void onListViewLinkClick(final ClickEvent event) {
    listViewLink.setStyleName(SELECTED_MENU_STYLE);
    mapViewLink.setStyleName(null);
    listViewPanel.setVisible(true);
    mapViewPanel.setVisible(false);
  }

  @UiHandler("mapViewLink")
  protected void onMapViewLinkClick(final ClickEvent event) {
    mapViewLink.setStyleName(SELECTED_MENU_STYLE);
    listViewLink.setStyleName(null);
    listViewPanel.setVisible(false);
    mapViewPanel.setVisible(true);
  }

  @UiHandler("selectDistrictLink")
  protected void onMapDialogLinkClick(final ClickEvent event) {
    // Create the dialog box
    final DialogBox dialogBox = createDialogBox();
    dialogBox.setGlassEnabled(true);
    dialogBox.setAnimationEnabled(false);
    dialogBox.addStyleName("districtsPanel");
    dialogBox.center();
    dialogBox.show();
  }

  private void getUserLocation() {
    final Geolocation geolocation = Geolocation.getIfSupported();
    geolocation.getCurrentPosition(new Callback<Position, PositionError>() {

      public void onSuccess(final Position result) {
        map.setCenter(LatLng.newInstance(result.getCoordinates().getLatitude(), result.getCoordinates().getLongitude()));
      }

      public void onFailure(final PositionError reason) {
        LOG.log(Level.SEVERE, "Error setting map center", reason);
      }
    });
  }

  private void setListItem(final List<SeguriAppEntity> entitiessList) {
    if (entitiessList != null) {
      for (final SeguriAppEntity entity : entitiessList) {
        final Marker marker = new Marker(LatLng.newInstance(entity.getLatitude(), entity.getLongitude()));
        marker.addMarkerClickHandler(new MarkerClickHandler() {

          public void onClick(MarkerClickEvent event) {
            InfoWindow info = map.getInfoWindow();
            info.open(event.getSender(), new InfoWindowContent("<span class='mapInfoText'>" + getMarketDescription(entity) + "</span>"));
          }
        });
        map.addOverlay(marker);
      }
    }
  }

  private String getMarketDescription(final SeguriAppEntity entity) {
    return entity.getTitle() + ": " + entity.getAddress();
  }

  private DialogBox createDialogBox() {
    // Create a dialog box and set the caption text
    final DialogBox dialogBox = new DialogBox();
    dialogBox.ensureDebugId("cwDialogBox");
    // Create a table to layout the content
    final VerticalPanel dialogContents = new VerticalPanel();
    dialogContents.setSpacing(4);
    dialogBox.setWidget(dialogContents);

    // Add some text to the top of the dialog
    final HorizontalPanel submitPanel = new HorizontalPanel();
    final List<Long> idsList = getSelectedList();
    final Button closeButton = new Button("Cerrar", new ClickHandler() {

      public void onClick(ClickEvent event) {
        updateCheckList(idsList);
        dialogBox.hide();
      }

    });
    final Button selectButton = new Button("Seleccionar", new ClickHandler() {

      public void onClick(ClickEvent event) {
        showSelectedItems();
        updateListData();
        dialogBox.hide();
      }

    });
    submitPanel.add(closeButton);
    dialogContents.setCellHorizontalAlignment(closeButton, HasHorizontalAlignment.ALIGN_CENTER);
    submitPanel.add(selectButton);
    dialogContents.setCellHorizontalAlignment(selectButton, HasHorizontalAlignment.ALIGN_CENTER);
    dialogContents.setHeight("300px");
    dialogContents.setWidth("500px");
    dialogContents.add(districtListOption);
    dialogContents.add(submitPanel);

    return dialogBox;
  }

  private void updateCheckList(final List<Long> idsList) {
    for (int i = 0; i < districtListOption.getWidgetCount(); i++) {
      final CheckBox checkbox = (CheckBox) districtListOption.getWidget(i);
      checkbox.setValue(false);
      for (final Long id : idsList) {
        if (checkbox.getFormValue().equals(id)) {
          checkbox.setValue(true);
          break;
        }
      }
    }
  }

  private void showSelectedItems() {
    selectedDistrictsPanel.clear();
    for (int i = 0; i < districtListOption.getWidgetCount(); i++) {
      final CheckBox checkbox = (CheckBox) districtListOption.getWidget(i);
      if (checkbox.getValue()) {
        final HTMLPanel panel = new HTMLPanel(checkbox.getText());
        panel.setStyleName("districtSelected");
        selectedDistrictsPanel.add(panel);
      }
    }
  }

}
